package com.yyfax.pay.depository.service.inner.impl;

import java.util.Date;
import java.util.List;

import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import com.yyfax.commons.lang.DateUtil;
import com.yyfax.framework.common.Log;
import com.yyfax.pay.common.constants.FuiouDepositConstant;
import com.yyfax.pay.common.enums.FuiouBusiTypeEnum;
import com.yyfax.pay.common.enums.FuiouDepositRspCodeEnum;
import com.yyfax.pay.common.enums.FuiouDepositStateEnum;
import com.yyfax.pay.common.exception.PayExceptionCode;
import com.yyfax.pay.common.model.vo.PayRspCodeVO;
import com.yyfax.pay.common.util.FuiouIdUtils;
import com.yyfax.pay.depository.dao.FuiouFrozenAppropriateDao;
import com.yyfax.pay.depository.dao.FuiouFrozenDao;
import com.yyfax.pay.depository.dao.FuiouFrozenToFrozenDao;
import com.yyfax.pay.depository.dao.FuiouFrozenTransferDao;
import com.yyfax.pay.depository.dao.FuiouTransferMerchantUserDao;
import com.yyfax.pay.depository.dao.FuiouTransferUserUserDao;
import com.yyfax.pay.depository.dao.FuiouUnfrozenDao;
import com.yyfax.pay.depository.service.inner.TradeQueryService;
import com.yyfax.pay.depository.to.TradeQueryReq;
import com.yyfax.pay.depository.vo.FuiouResponseVO;
import com.yyfax.pay.depository.vo.TradeQueryVO;
import com.yyfax.pay.order.model.vo.PayBusiIdVO;
import com.yyfax.pay.third.facade.fuioudeposit.FuiouDepositService;
import com.yyfax.pay.third.facade.fuioudeposit.FuiouSignService;
import com.yyfax.pay.third.model.to.fuioudeposit.FuiouDepositConfigExt;
import com.yyfax.pay.third.model.to.fuioudeposit.TradeQueryResultXMLRsp;
import com.yyfax.pay.third.model.to.fuioudeposit.TradeQueryResultXMLRsp.TradePlain;
import com.yyfax.pay.third.model.to.fuioudeposit.TradeQueryResultXMLRsp.TradeQueryRst;

/**
 * 交易查询服务实现
 * 
 * @author heizq
 * @date 2017-09-11 09:49:28
 * @since v1.0.0
 */
@Service
public class TradeQueryServiceImpl implements TradeQueryService {

	private static final Logger logger = LoggerFactory.getLogger(TradeQueryServiceImpl.class);

	@Resource
	private FuiouDepositService fuiouDepositService;

	@Resource
	private FuiouSignService fuiouSignService;

	@Resource
	private FuiouIdUtils fuiouIdUtils;

	@Resource
	private FuiouDepositConstant fuiouDepositConstant;

	@Resource
	private FuiouFrozenDao fuiouFrozenDao;

	@Resource
	private FuiouFrozenTransferDao fuiouFrozenTransferDao;

	@Resource
	private FuiouFrozenAppropriateDao fuiouFrozenAppropriateDao;

	@Resource
	private FuiouFrozenToFrozenDao fuiouFrozenToFrozenDao;

	@Resource
	private FuiouUnfrozenDao fuiouUnfrozenDao;

	@Resource
	private FuiouTransferMerchantUserDao transferMerchantUserDao;

	@Resource
	private FuiouTransferUserUserDao transferUserUserDao;
	
	@Override
	public boolean tradeQuery(TradeQueryReq req, String merchantCode) {
		final String op = "TradeQueryServiceImpl.tradeQuery";
		FuiouDepositConfigExt extInfo = fuiouSignService.getFuiouDepositConfig(merchantCode);

		// 封装请求参数
		TradeQueryVO vo = buildReqParams(req, extInfo, merchantCode);

		// 发送请求
		FuiouResponseVO rsp = fuiouDepositService.postForResponseVO(vo, extInfo.getTradeQueryUrl(), merchantCode);
		
		if (rsp == null || FuiouResponseVO.TIMEOUT.equals(rsp.getResult())) {
			//若果连接超时，等待下次轮询
			return false;
		}

		// 解析结果
		TradeQueryResultXMLRsp result = TradeQueryResultXMLRsp.fromXml(rsp.getContent());
		logger.info(Log.op(op).msg("【富友存管-交易查询】成功！").kv("result", result.toString()).toString());
		return dealResult(result, req.getSearilNo());
	}

	/**
	 * 封装请求
	 * 
	 * @author heizq
	 * @date 2017-09-02 13:30:50
	 * @since v1.0.0
	 * @param domain
	 * @param extInfo
	 * @return
	 */
	private TradeQueryVO buildReqParams(TradeQueryReq req, FuiouDepositConfigExt extInfo, String merchantCode) {
		TradeQueryVO vo = new TradeQueryVO();
		vo.setMerchantId(extInfo.getMerchantId());
		vo.setMerchantSerialNo(System.currentTimeMillis() + "");
		vo.setBusiType(req.getTradeType().getType());
		vo.setStartDay(StringUtils.isBlank(req.getStartDate()) ? DateUtil.date2Str(fuiouDepositConstant.getTradeQueryStartDay(new Date()), "yyyyMMdd")
				: req.getStartDate());
		vo.setEndDay(StringUtils.isBlank(req.getEndDate()) ? DateUtil.date2Str(fuiouDepositConstant.getTradeQueryEndDay(new Date()), "yyyyMMdd")
				: req.getEndDate());
		vo.setBusiId(req.getSearilNo());
		vo.setSignature(fuiouSignService.getSign(merchantCode, vo));
		return vo;
	}

	/**
	 * 结果处理
	 * 
	 * @author heizq
	 * @date 2017-09-28 16:11:54
	 * @since v1.0.0
	 * @param rsp
	 * @return
	 */
	private boolean dealResult(TradeQueryResultXMLRsp rsp, String busiId) {
		final String op = "FuiouTradeQueryHandler.dealResult";
		if (rsp == null || rsp.getPlain() == null) {
			logger.info(Log.op(op).msg("【富友存管】交易查询失败，返回结果为空！").kv("rsp", rsp).toString());
			return false;
		}
		
		TradePlain plain = rsp.getPlain();
		if (!FuiouDepositRspCodeEnum.SUCCESS.getValue().equals(plain.getRespCode())) {
			logger.info(Log.op(op).msg("【富友存管】交易查询失败，请求状态异常！").kv("rspCode", plain.getRespCode()).kv("请求流水号", plain.getSerailNo()).toString());
			return false;
		}
		
		List<TradeQueryRst> list = plain.getResults();
		if (CollectionUtils.isEmpty(list)) {
			logger.info(Log.op(op).msg("【富友存管】交易查询结束，没有查到对应的交易记录！").kv("请求流水号", plain.getSerailNo()).toString());
			// 没有查到订单更新到库里面
			TradeQueryRst queryRst = new TradeQueryResultXMLRsp().new TradeQueryRst();
			queryRst.setBusiId(busiId);
			// 注意,如果富友存管返回的响应码和支付的响应码存在一样值的情况下,dealQueryResult会判断错误,所以这里不能转换为支付模块的响应码
			queryRst.setTradeRespCode(PayExceptionCode.ORDER_NOT_FOUND.getCode() + "");
			queryRst.setTradeRespDesc(PayExceptionCode.ORDER_NOT_FOUND.getDesc());

			// 原业务逻辑在订单不存在时,响应码转换错误,使用新方法,edit by wangjw since 2.0.8
			// dealQueryResult(queryRst);
			dealQueryResult(queryRst, false);
			return true;
		}

		// 根据订单号查肯定是只有一条
		TradeQueryRst queryRst = plain.getResults().get(0);

		// 原业务逻辑在订单不存在时,响应码转换错误,使用新方法,edit by wangjw since 2.0.8
		// dealQueryResult(queryRst);
		dealQueryResult(queryRst, true);

		logger.info(Log.op(op).msg("【富友存管】交易查询成功！").kv("请求流水号", plain.getSerailNo()).toString());
		return true;
	}

	/**
	 * 查询结果处理,用于更新订单状态
	 * <p>
	 * 根据旧逻辑,改动原有结构工作量太大,重构
	 * {@linkplain TradeQueryServiceImpl#dealQueryResult(TradeQueryRst)}
	 * ,新增isOrderExist参数做订单判断
	 * 
	 * @author wangjw
	 * @date 2018年1月26日 下午4:06:40
	 * @since 2.0.8
	 * @param queryRst
	 * @param isOrderExist
	 *        订单是否存在,true-表示订单存在,false-表示订单不存在
	 */
	private void dealQueryResult(TradeQueryRst queryRst, boolean isOrderExist) {
		final String op = "TradeQueryServiceImpl.dealQueryResult";
		PayBusiIdVO idVO = fuiouIdUtils.parserBusiId(queryRst.getBusiId());
		FuiouBusiTypeEnum busiType = idVO.getBusiType();
		PayRspCodeVO codeExp = fuiouDepositService.converToPayRspCode(queryRst.getTradeRespCode());

		switch (busiType) {
		// 冻结
		case FROZEN:
			if (!isOrderExist) {
				// 如果订单不存在 edit by wangjw since 2.0.8
				fuiouFrozenDao.updateStateByBusiId(FuiouDepositStateEnum.INI.getValue(), queryRst.getBusiId(), DateUtil.getCurrentDateTime(),
						PayExceptionCode.ORDER_NOT_FOUND.getCode(), PayExceptionCode.ORDER_NOT_FOUND.getDesc());
				break;
			}

			if (FuiouDepositRspCodeEnum.SUCCESS.getValue().equals(queryRst.getTradeRespCode())) {
				// 如果响应成功,则更新订单在状态为成功
				fuiouFrozenDao.updateStateByBusiId(FuiouDepositStateEnum.SUCCESS.getValue(), queryRst.getBusiId(), DateUtil.getCurrentDateTime(),
						PayExceptionCode.SUCCESS.getCode(), queryRst.getTradeRespDesc());
			} else {
				// 如果是其它响应码,则判断订单为失败
				fuiouFrozenDao.updateStateByBusiId(FuiouDepositStateEnum.FAIL.getValue(), queryRst.getBusiId(), DateUtil.getCurrentDateTime(),
						codeExp.getCode(), codeExp.getDesc());
			}
			break;
		// 转账预冻结
		case TRANSFER_FROZEN:
			if (FuiouDepositRspCodeEnum.SUCCESS.getValue().equals(queryRst.getTradeRespCode())) {
				fuiouFrozenTransferDao.updateStateByBusiId(FuiouDepositStateEnum.SUCCESS.getValue(), queryRst.getBusiId(),
						DateUtil.getCurrentDateTime(), PayExceptionCode.SUCCESS.getCode(), queryRst.getTradeRespDesc());
			} else {
				fuiouFrozenTransferDao.updateStateByBusiId(FuiouDepositStateEnum.FAIL.getValue(), queryRst.getBusiId(), DateUtil.getCurrentDateTime(),
						codeExp.getCode(), codeExp.getDesc());
			}
			break;
		// 划拨预冻结
		case APPROPRIATE_FROZEN:
			if (!isOrderExist) {
				// 如果订单不存在edit by wangjw since 2.0.8
				fuiouFrozenAppropriateDao.updateStateByBusiId(FuiouDepositStateEnum.INI.getValue(), queryRst.getBusiId(),
						DateUtil.getCurrentDateTime(), PayExceptionCode.ORDER_NOT_FOUND.getCode(), PayExceptionCode.ORDER_NOT_FOUND.getDesc());
				break;
			}

			if (FuiouDepositRspCodeEnum.SUCCESS.getValue().equals(queryRst.getTradeRespCode())) {
				fuiouFrozenAppropriateDao.updateStateByBusiId(FuiouDepositStateEnum.SUCCESS.getValue(), queryRst.getBusiId(),
						DateUtil.getCurrentDateTime(), PayExceptionCode.SUCCESS.getCode(), queryRst.getTradeRespDesc());
			} else {
				fuiouFrozenAppropriateDao.updateStateByBusiId(FuiouDepositStateEnum.FAIL.getValue(), queryRst.getBusiId(),
						DateUtil.getCurrentDateTime(), codeExp.getCode(), codeExp.getDesc());
			}
			break;
		// 冻结到冻结
		case FROZEN_TO_FRONZEN:
			if (!isOrderExist) {
				// 如果订单不存在edit by wangjw since 2.0.8
				fuiouFrozenToFrozenDao.updateStateByBusiId(FuiouDepositStateEnum.INI.getValue(), queryRst.getBusiId(), DateUtil.getCurrentDateTime(),
						PayExceptionCode.ORDER_NOT_FOUND.getCode(), PayExceptionCode.ORDER_NOT_FOUND.getDesc());

				break;
			}
			if (FuiouDepositRspCodeEnum.SUCCESS.getValue().equals(queryRst.getTradeRespCode())) {
				fuiouFrozenToFrozenDao.updateStateByBusiId(FuiouDepositStateEnum.SUCCESS.getValue(), queryRst.getBusiId(),
						DateUtil.getCurrentDateTime(), PayExceptionCode.SUCCESS.getCode(), queryRst.getTradeRespDesc());
			} else {
				fuiouFrozenToFrozenDao.updateStateByBusiId(FuiouDepositStateEnum.FAIL.getValue(), queryRst.getBusiId(), DateUtil.getCurrentDateTime(),
						codeExp.getCode(), codeExp.getDesc());
			}
			break;
		// 解冻
		case UNFROZEN:
			if (!isOrderExist) {
				// 如果订单不存在edit by wangjw since 2.0.8
				fuiouUnfrozenDao.updateStateByBusiId(FuiouDepositStateEnum.INI.getValue(), queryRst.getBusiId(), DateUtil.getCurrentDateTime(),
						PayExceptionCode.ORDER_NOT_FOUND.getCode(), PayExceptionCode.ORDER_NOT_FOUND.getDesc());

				break;
			}
			if (FuiouDepositRspCodeEnum.SUCCESS.getValue().equals(queryRst.getTradeRespCode())) {
				fuiouUnfrozenDao.updateStateByBusiId(FuiouDepositStateEnum.SUCCESS.getValue(), queryRst.getBusiId(), DateUtil.getCurrentDateTime(),
						PayExceptionCode.SUCCESS.getCode(), queryRst.getTradeRespDesc());
			} else {
				fuiouUnfrozenDao.updateStateByBusiId(FuiouDepositStateEnum.FAIL.getValue(), queryRst.getBusiId(), DateUtil.getCurrentDateTime(),
						codeExp.getCode(), codeExp.getDesc());
			}
			break;
		// 划拨
		case TRANSFER_MERCHANT_USER:
			if (FuiouDepositRspCodeEnum.SUCCESS.getValue().equals(queryRst.getTradeRespCode())) {
				transferMerchantUserDao.updateStateRspByBusiId(FuiouDepositStateEnum.SUCCESS.getValue(), queryRst.getBusiId(),
						DateUtil.getCurrentDateTime(), PayExceptionCode.SUCCESS.getCode(), queryRst.getTradeRespDesc());
			} else {
				transferMerchantUserDao.updateStateRspByBusiId(FuiouDepositStateEnum.FAIL.getValue(), queryRst.getBusiId(),
						DateUtil.getCurrentDateTime(), codeExp.getCode(), codeExp.getDesc());
			}
			break;
		// 转账
		case TRANSFER_USER_USER:
			if (FuiouDepositRspCodeEnum.SUCCESS.getValue().equals(queryRst.getTradeRespCode())) {
				transferUserUserDao.updateStateRspByBusiId(FuiouDepositStateEnum.SUCCESS.getValue(), queryRst.getBusiId(),
						DateUtil.getCurrentDateTime(), PayExceptionCode.SUCCESS.getCode(), queryRst.getTradeRespDesc());
			} else {
				transferUserUserDao.updateStateRspByBusiId(FuiouDepositStateEnum.FAIL.getValue(), queryRst.getBusiId(), DateUtil.getCurrentDateTime(),
						codeExp.getCode(), codeExp.getDesc());
			}
			break;
		default:
			logger.warn(Log.op(op).msg("【富友存管-交易通知】业务类型错误！").kv("busiId", queryRst.getBusiId()).toString());
			break;
		}
	}

	/**
	 * 查询结果处理
	 * 
	 * @author heizq
	 * @date 2017-09-28 16:10:41
	 * @since v1.0.0
	 * @param queryRst
	 * @deprecated 作废该方法,使用
	 *             {@linkplain TradeQueryServiceImpl#dealQueryResult(TradeQueryRst, boolean)}
	 *             edit by wangjw since 2.0.8
	 */
	private void dealQueryResult(TradeQueryRst queryRst) {
		final String op = "TradeQueryServiceImpl.dealQueryResult";
		PayBusiIdVO idVO = fuiouIdUtils.parserBusiId(queryRst.getBusiId());
		FuiouBusiTypeEnum busiType = idVO.getBusiType();
		PayRspCodeVO codeExp = fuiouDepositService.converToPayRspCode(queryRst.getTradeRespCode());
		switch (busiType) {
		// 冻结
		case FROZEN:
			if (!FuiouDepositRspCodeEnum.SUCCESS.getValue().equals(queryRst.getTradeRespCode())) {
				fuiouFrozenDao.updateStateByBusiId(FuiouDepositStateEnum.FAIL.getValue(), queryRst.getBusiId(), DateUtil.getCurrentDateTime(),
						codeExp.getCode(), codeExp.getDesc());
			} else {
				fuiouFrozenDao.updateStateByBusiId(FuiouDepositStateEnum.SUCCESS.getValue(), queryRst.getBusiId(), DateUtil.getCurrentDateTime(),
						PayExceptionCode.SUCCESS.getCode(), queryRst.getTradeRespDesc());
			}
			break;
		// 转账预冻结
		case TRANSFER_FROZEN:
			if (!FuiouDepositRspCodeEnum.SUCCESS.getValue().equals(queryRst.getTradeRespCode())) {
				fuiouFrozenTransferDao.updateStateByBusiId(FuiouDepositStateEnum.FAIL.getValue(), queryRst.getBusiId(), DateUtil.getCurrentDateTime(),
						codeExp.getCode(), codeExp.getDesc());
			} else {
				fuiouFrozenTransferDao.updateStateByBusiId(FuiouDepositStateEnum.SUCCESS.getValue(), queryRst.getBusiId(),
						DateUtil.getCurrentDateTime(), PayExceptionCode.SUCCESS.getCode(), queryRst.getTradeRespDesc());
			}
			break;
		// 划拨预冻结
		case APPROPRIATE_FROZEN:
			if (!FuiouDepositRspCodeEnum.SUCCESS.getValue().equals(queryRst.getTradeRespCode())) {
				fuiouFrozenAppropriateDao.updateStateByBusiId(FuiouDepositStateEnum.FAIL.getValue(), queryRst.getBusiId(),
						DateUtil.getCurrentDateTime(), codeExp.getCode(), codeExp.getDesc());
			} else {
				fuiouFrozenAppropriateDao.updateStateByBusiId(FuiouDepositStateEnum.SUCCESS.getValue(), queryRst.getBusiId(),
						DateUtil.getCurrentDateTime(), PayExceptionCode.SUCCESS.getCode(), queryRst.getTradeRespDesc());
			}
			break;
		// 冻结到冻结
		case FROZEN_TO_FRONZEN:
			if (!FuiouDepositRspCodeEnum.SUCCESS.getValue().equals(queryRst.getTradeRespCode())) {
				fuiouFrozenToFrozenDao.updateStateByBusiId(FuiouDepositStateEnum.FAIL.getValue(), queryRst.getBusiId(), DateUtil.getCurrentDateTime(),
						codeExp.getCode(), codeExp.getDesc());
			} else {
				fuiouFrozenToFrozenDao.updateStateByBusiId(FuiouDepositStateEnum.SUCCESS.getValue(), queryRst.getBusiId(),
						DateUtil.getCurrentDateTime(), PayExceptionCode.SUCCESS.getCode(), queryRst.getTradeRespDesc());
			}
			break;
		// 解冻
		case UNFROZEN:
			if (!FuiouDepositRspCodeEnum.SUCCESS.getValue().equals(queryRst.getTradeRespCode())) {
				fuiouUnfrozenDao.updateStateByBusiId(FuiouDepositStateEnum.FAIL.getValue(), queryRst.getBusiId(), DateUtil.getCurrentDateTime(),
						codeExp.getCode(), codeExp.getDesc());
			} else {
				fuiouUnfrozenDao.updateStateByBusiId(FuiouDepositStateEnum.SUCCESS.getValue(), queryRst.getBusiId(), DateUtil.getCurrentDateTime(),
						PayExceptionCode.SUCCESS.getCode(), queryRst.getTradeRespDesc());
			}
			break;
		// 划拨
		case TRANSFER_MERCHANT_USER:
			if (!FuiouDepositRspCodeEnum.SUCCESS.getValue().equals(queryRst.getTradeRespCode())) {
				transferMerchantUserDao.updateStateRspByBusiId(FuiouDepositStateEnum.FAIL.getValue(), queryRst.getBusiId(),
						DateUtil.getCurrentDateTime(), codeExp.getCode(), codeExp.getDesc());
			} else {
				transferMerchantUserDao.updateStateRspByBusiId(FuiouDepositStateEnum.SUCCESS.getValue(), queryRst.getBusiId(),
						DateUtil.getCurrentDateTime(), PayExceptionCode.SUCCESS.getCode(), queryRst.getTradeRespDesc());
			}
			break;
		// 转账
		case TRANSFER_USER_USER:
			if (!FuiouDepositRspCodeEnum.SUCCESS.getValue().equals(queryRst.getTradeRespCode())) {
				transferUserUserDao.updateStateRspByBusiId(FuiouDepositStateEnum.FAIL.getValue(), queryRst.getBusiId(), DateUtil.getCurrentDateTime(),
						codeExp.getCode(), codeExp.getDesc());
			} else {
				transferUserUserDao.updateStateRspByBusiId(FuiouDepositStateEnum.SUCCESS.getValue(), queryRst.getBusiId(),
						DateUtil.getCurrentDateTime(), PayExceptionCode.SUCCESS.getCode(), queryRst.getTradeRespDesc());
			}
			break;
		default:
			logger.warn(Log.op(op).msg("【富友存管-交易通知】业务类型错误！").kv("busiId", queryRst.getBusiId()).toString());
			break;
		}
	}
}
